
#include "EPDADeserializer.h"

EPDADeserializer::EPDADeserializer()
{
	pEPDA = new EPDA();
}

EPDA* EPDADeserializer::getEPDA()
{
	return pEPDA;
}

bool EPDADeserializer::load(const char *pFilename)
{
	TiXmlDocument modelDoc(pFilename);
	if (!modelDoc.LoadFile()) throw "Model file open failed!";

	TiXmlElement* root = modelDoc.FirstChildElement("class");
	for (TiXmlElement* pNode = root->FirstChildElement(); pNode; pNode = pNode->NextSiblingElement())
	{
		if (strcmp("variable", pNode->Value()) == 0)
			pEPDA->addVariable(parseVariable(pNode));
		else if (strcmp("state", pNode->Value()) == 0)
		{
			if (!pNode->Attribute("id")) throw "Id missed for state in model file!";
			int index = atoi(pNode->Attribute("id"));
			pEPDA->addState(index, parseState(pNode));
		}
		else throw "Invalid xml element for class";
	}
	return true;
}

EPDADeserializer::~EPDADeserializer()
{
	delete pEPDA;
}

Variable EPDADeserializer::parseVariable(TiXmlElement* pNode)
{
	Variable var;
	TiXmlElement* pSub;
	if (pSub = pNode->FirstChildElement("name"))
		var.setName(pSub->GetText());
	if(pSub = pNode->FirstChildElement("type")) 
		var.setType(pSub->GetText());
	if(pSub = pNode->FirstChildElement("init")) 
		var.setValue(pSub->GetText());
	return var;
}

State EPDADeserializer::parseState(TiXmlElement* pNode)
{
	State state;	
	for (pNode = pNode->FirstChildElement(); pNode; pNode = pNode->NextSiblingElement())
		state.addTransition(parseTransition(pNode));
	return state;
}

Transition EPDADeserializer::parseTransition(TiXmlElement* pNode)
{
	Method method = parseMethod(pNode->FirstChildElement("method"));
	int tail = atoi(pNode->Attribute("tail"));
	Transition tran(method, tail);

	TiXmlElement* pCond = pNode->FirstChildElement("conditions");
	if (pCond)
	{
		for (pCond = pCond->FirstChildElement(); pCond; pCond = pCond->NextSiblingElement())
			parseCondition(pCond, &tran);
	}

	TiXmlElement* pAction = pNode->FirstChildElement("actions");
	if (pAction)
	{
		for (pAction = pAction->FirstChildElement(); pAction; pAction = pAction->NextSiblingElement())
			parseAction(pAction, &tran);
	}

	return tran;
}

void EPDADeserializer::parseAction(TiXmlElement* pAction, Transition* tran)
{
	if (!pAction->Attribute("type")) throw "Type missed for action node!";
	if (strcmp("STACK", pAction->Attribute("type")) == 0)
	{
		StackAction stackAction = pEPDA->createStackAction();

		TiXmlElement* pNode = pAction->FirstChildElement("operation");
		if (!pNode) throw "Operation missed for stack action node!";
		stackAction.setOperation(pNode->GetText());

		pNode = pAction->FirstChildElement("value");
		if (!pNode) throw "Value missed for stack action node!";
		stackAction.setValue(atoi(pNode->GetText()));
		tran->addAction(stackAction);
	}
	else throw "Invalid type of action!";
}

Method EPDADeserializer::parseMethod(TiXmlElement *pNode)
{
	string name(pNode->Attribute("name"));
	Method method(name);
	for (pNode = pNode->FirstChildElement(); pNode; pNode = pNode->NextSiblingElement())
	{
		string type(pNode->Attribute("type"));
		method.addPara(type);
	}
	pEPDA->registerMethod(name);
	return method;
}

void EPDADeserializer::parseCondition(TiXmlElement* pNode, Transition* tran)
{
	if (!pNode->Attribute("type")) throw "Type missed for condition node!";
	TiXmlElement* pSet = pNode->FirstChildElement("sets");
	if (strcmp("PARAMETER", pNode->Attribute("type")) == 0)
	{
		int target = atoi(pNode->Attribute("target"));
		ParaCondition paraCond(target);
		for (pSet = pSet->FirstChildElement(); pSet; pSet = pSet->NextSiblingElement())
			parsePredicate(pSet, &paraCond);
		tran->addCondition(paraCond);
	} 
	else if(strcmp("STACK", pNode->Attribute("type")) == 0)
	{
		StackCondition stackCond = pEPDA->createStackCondition();
		for (pSet = pSet->FirstChildElement(); pSet; pSet = pSet->NextSiblingElement())
			parsePredicate(pSet, &stackCond);
		tran->addCondition(stackCond);
	}
	else throw "Invalid type for condition in model file!";
}

void EPDADeserializer::parsePredicate(TiXmlElement* pNode, Condition* cond)
{
	TiXmlElement* pVal = pNode->FirstChildElement("value");
	string val(pVal ? pVal->GetText() : "");
	
	if (!pNode->Attribute("relation")) throw "Relation missed for predicate node!";
	if (strcmp("EQUAL", pNode->Attribute("relation")) == 0)
		cond->addPredicate(StrEqlPre(val));
	else throw "Invalid relation for predicate!";
}
